package backed.service.impl;

import backed.entity.GarbageClassification;
import backed.repository.GarbageSortRepository;
import backed.service.FileUploadService;
import backed.service.GarbageSortService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 垃圾分类服务实现类
 */
@Service
public class GarbageSortServiceImpl implements GarbageSortService {
    
    @Autowired
    private GarbageSortRepository repository;
    
    @Autowired
    private FileUploadService fileUploadService;
    
    private final WebClient webClient;
    
    private static final String GARBAGE_BOT_ID = "7578399111062601728";
    
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    public GarbageSortServiceImpl() {
        this.webClient = WebClient.builder()
                .baseUrl("https://api.coze.cn/v3")
                .defaultHeader("Authorization", "Bearer pat_9irnbeU2KfAG1HaCyBnOQYyhdRCt7IHsTncywyFRY82fQ8GbXlpBIYeGaatUQ6EK")
                .build();
    }
    
    @PostConstruct
    public void init() {
        System.out.println("√ 垃圾分类服务模块初始化完成...");
    }
    
    @Override
    public Map<String, Object> classifyGarbage(Long userId, MultipartFile imageFile, String question) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 1. 上传图片到COS
            String imageUrl = fileUploadService.uploadFile(imageFile, userId);
            
            // 2. 构建请求消息，直接传递图片URL
            String requestMessage = buildRequestMessage(question, imageUrl);
            
            // 3. 调用Coze AI
            String aiResponse = callCozeStream(requestMessage, userId);
            
            // 添加调试日志，查看AI的完整响应
            System.out.println("========== AI完整响应 ==========");
            System.out.println(aiResponse);
            System.out.println("=================================");
            
            // 4. 解析AI返回的结果
            ParsedResult parsed = parseAIResponse(aiResponse);
            
            // 添加调试日志，查看解析结果
            System.out.println("解析结果 - itemName: " + parsed.itemName);
            System.out.println("解析结果 - category: " + parsed.category);
            System.out.println("解析结果 - suggestion: " + parsed.suggestion);
            
            // 5. 保存到数据库
            GarbageClassification record = new GarbageClassification();
            record.setUserId(userId);
            record.setImageUrl(imageUrl);
            record.setQuestion(question != null ? question.trim() : null);
            record.setItemName(parsed.itemName);
            record.setCategory(parsed.category);
            record.setSuggestion(parsed.suggestion);
            repository.save(record);
            
            // 6. 构建返回结果
            result.put("success", true);
            Map<String, Object> data = new HashMap<>();
            data.put("itemName", parsed.itemName);
            data.put("category", parsed.category);
            data.put("suggestion", parsed.suggestion);
            data.put("imageUrl", imageUrl);
            if (question != null) {
                data.put("question", question);
            }
            result.put("data", data);
            
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "垃圾分类识别失败: " + e.getMessage());
            result.put("data", new HashMap<>());
        }
        
        return result;
    }
    
    @Override
    public List<Map<String, Object>> getHistory(Long userId) {
        List<GarbageClassification> records = repository.findByUserIdOrderByCreateTimeDesc(userId);
        List<Map<String, Object>> result = new ArrayList<>();
        
        for (GarbageClassification record : records) {
            Map<String, Object> item = new HashMap<>();
            item.put("id", record.getId());
            item.put("itemName", record.getItemName());
            item.put("category", record.getCategory());
            item.put("suggestion", record.getSuggestion());
            item.put("imageUrl", record.getImageUrl());
            item.put("question", record.getQuestion());
            item.put("createTime", record.getCreateTime());
            result.add(item);
        }
        
        return result;
    }
    
    /**
     * 构建请求消息
     * 按照Coze官方规范：图片URL + 问题文本，都在content字段中
     */
    private String buildRequestMessage(String question, String imageUrl) {
        // 按照Coze官方规范：图片URL + 问题文本
        String questionText = (question != null && !question.trim().isEmpty()) 
            ? question.trim() 
            : "这是什么垃圾";
        
        // 在问题后添加格式要求，明确要求AI返回"物品名称：xxx"格式
        String formattedQuestion = questionText + "。请返回格式：物品名称：xxx";
        
        // 格式：图片URL + 问题文本（顺序不能错）
        return imageUrl + formattedQuestion;
    }
    
    /**
     * 调用Coze AI流式接口
     */
    private String callCozeStream(String message, Long userId) {
        try {
            String requestBody = buildRequestBody(userId, message);
            
            Flux<String> stream = webClient.post()
                    .uri("/chat")
                    .header("Content-Type", "application/json")
                    .header("Accept", "text/event-stream")
                    .bodyValue(requestBody)
                    .retrieve()
                    .onStatus(status -> status.is4xxClientError() || status.is5xxServerError(),
                        response -> response.bodyToMono(String.class)
                                .then(Mono.error(new RuntimeException("API 请求失败: " + response.statusCode()))))
                    .bodyToFlux(String.class);
            
            return processStreamResponse(stream);
            
        } catch (Exception e) {
            throw new RuntimeException("调用AI服务失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 构建请求体
     */
    private String buildRequestBody(Long userId, String message) {
        try {
            Map<String, Object> body = new HashMap<>();
            body.put("bot_id", GARBAGE_BOT_ID);
            body.put("user_id", String.valueOf(userId));
            body.put("stream", true);
            
            List<Map<String, String>> messages = new ArrayList<>();
            Map<String, String> userMessage = new HashMap<>();
            userMessage.put("role", "user");
            userMessage.put("type", "question");
            userMessage.put("content_type", "text");
            userMessage.put("content", message);
            messages.add(userMessage);
            body.put("additional_messages", messages);
            
            return objectMapper.writeValueAsString(body);
        } catch (Exception e) {
            throw new RuntimeException("构建请求体失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 处理流式响应
     */
    private String processStreamResponse(Flux<String> stream) {
        StringBuilder fullAnswer = new StringBuilder();
        Set<String> processed = new HashSet<>();
        final boolean[] hasError = {false};
        final String[] errorMessage = {null};
        
        try {
            stream
                .doOnNext(dataChunk -> {
                    try {
                        String jsonData = cleanStreamData(dataChunk);
                        if (jsonData == null) return;
                        
                        JsonNode node = objectMapper.readTree(jsonData);
                        
                        if (checkForError(node)) {
                            hasError[0] = true;
                            errorMessage[0] = extractErrorMessage(node);
                            return;
                        }
                        
                        String content = extractAnswerContent(node);
                        if (content != null && !content.isEmpty()) {
                            if (!processed.contains(content)) {
                                processed.add(content);
                                fullAnswer.append(content);
                            }
                        }
                    } catch (Exception e) {
                        // 忽略单条数据解析错误
                    }
                })
                .doOnError(error -> {
                    hasError[0] = true;
                    errorMessage[0] = "流式请求错误: " + error.getMessage();
                })
                .blockLast(Duration.ofMinutes(5));
            
            if (hasError[0]) {
                throw new RuntimeException(errorMessage[0] != null ? errorMessage[0] : "请求处理失败");
            }
            
            if (fullAnswer.length() == 0) {
                throw new RuntimeException("未收到有效响应内容");
            }
            
            return fullAnswer.toString();
            
        } catch (Exception e) {
            throw new RuntimeException("处理响应时发生错误: " + e.getMessage(), e);
        }
    }
    
    /**
     * 清理流式数据
     */
    private String cleanStreamData(String data) {
        String jsonData = data.trim();
        if (jsonData.startsWith("data: ")) {
            jsonData = jsonData.substring(6);
        }
        if (jsonData.isEmpty() || jsonData.startsWith(":")) {
            return null;
        }
        return jsonData;
    }
    
    /**
     * 检查是否有错误
     */
    private boolean checkForError(JsonNode node) {
        if (node.has("code")) {
            return true;
        }
        if (node.has("last_error")) {
            JsonNode lastError = node.get("last_error");
            if (lastError.has("code")) {
                int errorCode = lastError.get("code").asInt();
                if (errorCode != 0) return true;
            }
        }
        if (node.has("status")) {
            String status = node.get("status").asText();
            if ("failed".equals(status) || "cancelled".equals(status)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 提取错误信息
     */
    private String extractErrorMessage(JsonNode node) {
        if (node.has("code")) {
            int code = node.get("code").asInt();
            String msg = node.has("msg") ? node.get("msg").asText() : "未知错误";
            return String.format("API错误 [code: %d, msg: %s]", code, msg);
        }
        if (node.has("last_error")) {
            JsonNode lastError = node.get("last_error");
            if (lastError.has("code")) {
                int errorCode = lastError.get("code").asInt();
                if (errorCode != 0) {
                    String errorMsg = lastError.has("msg") ? lastError.get("msg").asText() : "未知错误";
                    return String.format("任务执行错误 [code: %d, msg: %s]", errorCode, errorMsg);
                }
            }
        }
        return "未知错误";
    }
    
    /**
     * 提取答案内容
     */
    private String extractAnswerContent(JsonNode node) {
        if (!node.has("type")) {
            return null;
        }
        if (node.has("status")) {
            return null;
        }
        
        String type = node.get("type").asText();
        if ("answer".equals(type) || "final_answer".equals(type)) {
            if (node.has("content")) {
                return node.get("content").asText();
            }
        }
        
        return null;
    }
    
    /**
     * 解析AI返回的结果
     * 从AI的文本或JSON响应中提取itemName、category、suggestion
     */
    private ParsedResult parseAIResponse(String aiResponse) {
        ParsedResult result = new ParsedResult();
        
        if (aiResponse == null || aiResponse.trim().isEmpty()) {
            return result;
        }
        
        // 先尝试解析JSON格式
        try {
            JsonNode jsonNode = objectMapper.readTree(aiResponse);
            if (jsonNode.has("itemName")) {
                result.itemName = jsonNode.get("itemName").asText();
            }
            if (jsonNode.has("category")) {
                result.category = normalizeCategory(jsonNode.get("category").asText());
            }
            if (jsonNode.has("suggestion")) {
                result.suggestion = jsonNode.get("suggestion").asText();
            }
            if (result.itemName != null && result.category != null) {
                return result;
            }
        } catch (Exception e) {
            // 不是JSON格式，继续用文本解析
        }
        
        // 尝试从JSON代码块中提取
        String jsonInCodeBlock = extractJsonFromCodeBlock(aiResponse);
        if (jsonInCodeBlock != null) {
            try {
                JsonNode jsonNode = objectMapper.readTree(jsonInCodeBlock);
                if (jsonNode.has("itemName")) {
                    result.itemName = jsonNode.get("itemName").asText();
                }
                if (jsonNode.has("category")) {
                    result.category = normalizeCategory(jsonNode.get("category").asText());
                }
                if (jsonNode.has("suggestion")) {
                    result.suggestion = jsonNode.get("suggestion").asText();
                }
                if (result.itemName != null && result.category != null) {
                    return result;
                }
            } catch (Exception e) {
                // 继续文本解析
            }
        }
        
        // 文本格式解析
        result.category = normalizeCategory(extractCategory(aiResponse));
        result.suggestion = extractSuggestion(aiResponse);
        
        // 优先从suggestion中提取itemName，因为AI通常在suggestion开头提及物品名称
        if (result.suggestion != null && !result.suggestion.isEmpty()) {
            result.itemName = extractItemName(result.suggestion);
        }
        
        // 如果从suggestion中没提取到，再从完整响应中提取
        if (result.itemName == null || result.itemName.isEmpty()) {
            result.itemName = extractItemName(aiResponse);
        }
        
        return result;
    }
    
    /**
     * 从代码块中提取JSON
     */
    private String extractJsonFromCodeBlock(String text) {
        Pattern pattern = Pattern.compile("```(?:json)?\\s*\\n?\\s*(\\{.*?\\})\\s*\\n?\\s*```", Pattern.DOTALL);
        Matcher matcher = pattern.matcher(text);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }
    
    /**
     * 提取物品名称
     */
    private String extractItemName(String text) {
        if (text == null || text.trim().isEmpty()) {
            return null;
        }
        
        // 尝试JSON格式
        Pattern jsonPattern = Pattern.compile("\"itemName\"\\s*:\\s*\"([^\"]+)\"", Pattern.CASE_INSENSITIVE);
        Matcher matcher = jsonPattern.matcher(text);
        if (matcher.find()) {
            String name = matcher.group(1).trim();
            if (!name.isEmpty() && !"null".equalsIgnoreCase(name)) {
                return name;
            }
        }
        
        // 优先匹配中文格式：物品名称：xxx（提取到遇到"（"为止）
        // 例如："物品名称：香蕉皮（xxx）" -> 提取"香蕉皮"，遇到"（"就停止
        Pattern chinesePattern = Pattern.compile("物品名称[：:]\\s*([^（\\(]+)");
        matcher = chinesePattern.matcher(text);
        if (matcher.find()) {
            String name = matcher.group(1).trim();
            if (!name.isEmpty()) {
                return name;
            }
        }
        
        // 尝试从suggestion开头提取：XX和XX都属于 / XX都属于
        // 例如："香蕉皮和果肉都属于易腐物" -> 提取"香蕉皮和果肉"或"香蕉皮"
        Pattern pattern1 = Pattern.compile("^([^，,。和与及、]{1,15}?)(?:和|与|及|、)([^，,。和与及、]{1,15}?)(?:都属于|属于)", Pattern.CASE_INSENSITIVE);
        matcher = pattern1.matcher(text);
        if (matcher.find()) {
            String name1 = matcher.group(1).trim();
            String name2 = matcher.group(2).trim();
            if (name1.length() > 0 && name1.length() <= 15 && name2.length() > 0 && name2.length() <= 15) {
                return name1 + "和" + name2;
            }
        }
        
        // 尝试提取单个物品名称：XX都属于/属于（不包含"和"的情况）
        // 例如："香蕉皮都属于易腐物" -> 提取"香蕉皮"
        Pattern pattern2 = Pattern.compile("^([^，,。和与及、]{1,15}?)(?:都属于|属于)(?:[易可有害厨其]|易腐)", Pattern.CASE_INSENSITIVE);
        matcher = pattern2.matcher(text);
        if (matcher.find()) {
            String name = matcher.group(1).trim();
            if (name.length() > 0 && name.length() <= 15 && 
                !name.matches(".*(?:这|那|它|您|记得|投放|一起|倒|在|里|的|它们).*")) {
                return name;
            }
        }
        
        // 尝试提取：XX属于XXX（简化版）
        Pattern pattern2b = Pattern.compile("^([^，,。和与及、]{1,15}?)(?:属于)", Pattern.CASE_INSENSITIVE);
        matcher = pattern2b.matcher(text);
        if (matcher.find()) {
            String name = matcher.group(1).trim();
            if (name.length() > 0 && name.length() <= 15 && 
                !name.matches(".*(?:这|那|它|您|记得|投放|一起|倒|在|里|的|它们).*")) {
                return name;
            }
        }
        
        // 尝试识别：这是XXX
        Pattern pattern3 = Pattern.compile("(?:这是|图中是|图片中是)([^，,。\\n属于]{1,15}?)(?:垃圾|属于|是)", Pattern.CASE_INSENSITIVE);
        matcher = pattern3.matcher(text);
        if (matcher.find()) {
            String name = matcher.group(1).trim();
            if (name.length() > 0 && name.length() <= 15) {
                return name;
            }
        }
        
        // 尝试从文本开头提取物品名称（在逗号、句号之前）
        Pattern pattern4 = Pattern.compile("^([^，,。\\n]{2,15}?)(?:和|与|及|、|都属于|属于|是|为)", Pattern.CASE_INSENSITIVE);
        matcher = pattern4.matcher(text.substring(0, Math.min(50, text.length())));
        if (matcher.find()) {
            String name = matcher.group(1).trim();
            if (name.length() >= 2 && name.length() <= 15 && 
                !name.matches(".*(?:这|那|它|您|记得|投放).*")) {
                return name;
            }
        }
        
        return null;
    }
    
    /**
     * 提取分类
     */
    private String extractCategory(String text) {
        // 尝试JSON格式
        Pattern jsonPattern = Pattern.compile("\"category\"\\s*:\\s*\"([^\"]+)\"", Pattern.CASE_INSENSITIVE);
        Matcher matcher = jsonPattern.matcher(text);
        if (matcher.find()) {
            return matcher.group(1);
        }
        
        // 尝试中文格式
        Pattern chinesePattern = Pattern.compile("分类[：:]\\s*([^\\n]+)");
        matcher = chinesePattern.matcher(text);
        if (matcher.find()) {
            return matcher.group(1).trim();
        }
        
        // 尝试识别关键词
        if (text.contains("可回收") || text.contains("可回收垃圾")) {
            return "可回收";
        }
        if (text.contains("有害") || text.contains("有害垃圾")) {
            return "有害";
        }
        if (text.contains("厨余") || text.contains("湿垃圾") || text.contains("易腐垃圾")) {
            return "厨余";
        }
        if (text.contains("其他") || text.contains("干垃圾")) {
            return "其他";
        }
        
        return null;
    }
    
    /**
     * 标准化分类名称
     */
    private String normalizeCategory(String category) {
        if (category == null) {
            return null;
        }
        
        category = category.trim();
        
        if (category.contains("可回收")) {
            return "可回收";
        }
        if (category.contains("有害")) {
            return "有害";
        }
        if (category.contains("厨余") || category.contains("湿垃圾") || category.contains("易腐")) {
            return "厨余";
        }
        if (category.contains("其他") || category.contains("干垃圾")) {
            return "其他";
        }
        
        return category;
    }
    
    /**
     * 提取建议
     */
    private String extractSuggestion(String text) {
        // 尝试JSON格式
        Pattern jsonPattern = Pattern.compile("\"suggestion\"\\s*:\\s*\"([^\"]+)\"", Pattern.CASE_INSENSITIVE);
        Matcher matcher = jsonPattern.matcher(text);
        if (matcher.find()) {
            return matcher.group(1);
        }
        
        // 尝试中文格式
        Pattern chinesePattern = Pattern.compile("建议[：:]\\s*([^\\n]+(?:\\n[^\\n]+)*)");
        matcher = chinesePattern.matcher(text);
        if (matcher.find()) {
            return matcher.group(1).trim();
        }
        
        // 提取投放建议部分
        Pattern suggestionPattern = Pattern.compile("投放建议[：:]\\s*([^\\n]+(?:\\n[^\\n]+)*)");
        matcher = suggestionPattern.matcher(text);
        if (matcher.find()) {
            return matcher.group(1).trim();
        }
        
        // 如果没有找到明确的建议字段，返回完整回答
        return text.trim();
    }
    
    /**
     * 解析结果内部类
     */
    private static class ParsedResult {
        String itemName;
        String category;
        String suggestion;
    }
}

